#pragma once

#include <iostream>
#include <string>
#include <vector>

#include <cstring>
#include <cstdlib>

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <jsoncpp/json/json.h>

#define MYSELF

//序列化和反序列化 处理函数

//规定函数参数:
// const& 输入
// *:输出
// &:输入输出

namespace protocol
{

#define SPE " "
#define SPE_LEN strlen(SPE)
#define HEADER_SPE "\r\n"
#define HEADER_SPE_LEN strlen(HEADER_SPE)


    //读取函数 返回读取的字节数 当读到一个完整的package包写入package参数返回
    int ReadPackage(int sockfd,std::string& inbuffer,std::string* package)
    {
        char buf[1024] = {0}; //读取缓冲区
        int n = recv(sockfd,buf,sizeof(buf)-1,0);
        if(n < 0) return -1; //如果读取失败返回-1
        else if(n == 0) return 0; //如果什么都没读取到则返回0

        buf[n] = '\0';
        inbuffer += buf; //无论是否完整 先讲buf写入inbuffer缓冲区 如果不完整则下次接着读并拼接在后面直到完整

        //报文形式"7\r\n10 + 30\r\n"
        //开始分析报文
        //1.获取报文长度
        auto pos = inbuffer.find(HEADER_SPE); //找到第一个/r/n 找到后返回第一个 / 的下标
        if(pos == std::string::npos) return 0; //如果没有则代表当前报文不完整 继续读完整

        //2.将首部存储的长度转换成数字
        std::string slen = inbuffer.substr(0,pos); //左闭右开区间 获取数字字符串 字符串长度是0-pos的长度
        int len = atoi(slen.c_str()); //讲获取的字符串长度转换成数字

        //3.求总报文大小(包括分隔字符)通过验算验证报文是否完整
        //报文应该的大小 = 内容大小len+报文首部数字长度+两个\r\n
        int targetPackageLen = slen.size()+len+(2*HEADER_SPE_LEN);
        if(inbuffer.size() < targetPackageLen) return 0; //如果验证读取的报文不完整 则继续读取 直到完整

        //5.将报文完整的交付 (但不做处理)
        *package = inbuffer.substr(0,targetPackageLen);
        inbuffer.erase(0,targetPackageLen);

        return len; //返回有效载荷的大小
        //注意:该函数只做报文的读取 验证完整性 并不做拆分 当报文完整则输出未处理的完整报文
        //该函数最终 返回完整报文+有效载荷的长度
    }

    // 提取有效载荷 len参数是有效载荷的长度
    std::string RemoveHeader(const std::string &str, int len)
    {
        //str.size()-HEADER_SPE_LEN-len 将下标定位到有效载荷的第一个字符
        //从有效载荷的第一个字符开始 读len个字符就获取到了有效载荷
        std::string ret = str.substr(str.size()-HEADER_SPE_LEN-len,len);
        return ret;
    }

    //验证运算符合法性
    bool operleg(char op)
    {
        if(op == '+' || op == '-' || op == '*' || op == '/' || op == '%') return true;
        return false;
    }


    //分割有效载荷 str=有效载荷  sep=有效载荷内容之间的分隔符  result=分割内容 分别为左操作数+运算符+右操作数
    static bool StringSplit(const std::string &str, const std::string &sep, std::vector<std::string> *result)
    {
        if(!result) return false; //如果输出参数为空则完成失败
        size_t start = 0; //下标从0开始

        int slen = str.size();
        while(start < slen) //遍历有效载荷 分割字符存入result
        {
            //10 + 30
            auto pos = str.find(sep,start); //开始查找分隔符
            if(pos == std::string::npos) break; //如果不存在则跳出循环

            result->push_back(str.substr(start,pos-start)); //写入第一个数字
            start = pos+sep.size(); //将下标定位到下一个 字符的下标位置(下一个下标位置是运算符)
        }

        if(start < slen) result->push_back(str.substr(start,slen)); //while循环中在右操作数时会跳出
        
        return true;
    }

    //响应包报头
    std::string AddHeader(const std::string& str)
    {
        std::string ret = std::to_string(str.size()); //先写入有效载荷大小
        ret += HEADER_SPE; //添加/r/n
        ret += str; //添加有效载荷
        ret += HEADER_SPE; //添加尾部/r/n

        return ret; //返回新报文
    }

    //请求包
    class Request
    {
    public: 
        Request()= default; //生成默认构造
        Request(int x,int y,char op)
            :_x(x)
            ,_y(y)
            ,_op(op)
        {}

        //将有效载荷分离 初始化请求包对象  10 + 20
        bool Deserialize(const std::string &inStr)
        {
#ifdef MYSELF
            std::vector<std::string> result;
            if(!StringSplit(inStr,SPE,&result)) return false; //如果分割不成功 则false
            else if(result.size() != 3) return false; //如果分割的内容不对 则false

            _x = atoi(result[0].c_str());
            _y = atoi(result[2].c_str());
            _op = result[1][0];
#else
            Json::Value root; //万能序列化KV模型
            Json::Reader reader; // Reader: 用来进行反序列化的
            reader.parse(inStr, root);

            _x = root["x"].asInt();
            _y = root["y"].asInt();
            _op = root["op"].asInt(); //char也是整形


#endif
            return true;
        }

        //将请求包序列化并输出
        bool Serialize(std::string* outStr)
        {
            if(!outStr) return false; //如果为空则false
            outStr->clear();//清空原字符串
#ifdef MYSELF
            (*outStr) = std::to_string(_x) + SPE + _op + SPE + std::to_string(_y);
#else
            Json::Value root; //万能对象，接受任意KV类型
            root["x"] = _x;
            root["y"] = _y;
            root["op"] = _op;
            Json::FastWriter writer;
            //Json::StyledWriter writer; //将kv字段添加\r\n使其更好看更好调试
            *outStr = writer.write(root);
#endif

            return true;
        }

        void Print() { std::cout<<_x<<_op<<_y<<std::endl; }

    public:
        int _x; //左操作数
        int _y; //右操作数
        char _op; //运算符号

    };


    const char* err_str[4] = {" success"," / zero"," % zero"," unkown error"};
    class Response
    {
    public:
        Response() = default;
        Response(int result,int code)
            :_result(result)
            ,_code(code)
        {}

        //形成响应包 并返回处理结果
        bool Serialize(std::string *outStr)
        {
            if(!outStr) return false; //如果指针为空则失败
            outStr->clear(); //清空返回值字符串
#ifdef MYSELF
            (*outStr) = std::to_string(_result) + SPE + std::to_string(_code); //手动序列化
#else
            Json::Value root;
            root["result"] = _result;
            root["code"] = _code;

            // Json::FastWriter writer;
            Json::StyledWriter writer;

            *outStr = writer.write(root);
#endif
            return true;
        }

        //将响应数据放序列化放入响应包 _result _code
        bool Deserialize(const std::string &inStr)
        {
#ifdef MYSELF
            std::vector<std::string> ret;
            if(!StringSplit(inStr,SPE,&ret)) return false;
            if(ret.size() != 2) return false;
            _result = atoi(ret[0].c_str());
            _code = atoi(ret[1].c_str());
#else
            Json::Value root;
            Json::Reader reader;
            reader.parse(inStr, root);
            _result = root["result"].asInt();
            _code = root["code"].asInt();
#endif
            return true;
        }

        void Print() { std::cout<<"result:"<<_result<<" (code:"<<_code<<"|"<<err_str[_code]<<")"<<std::endl; }

    public:
        int _result; //返回值
        int _code; // [0 = success] -> 1,2,3,4代表不同的错误码
        
    };



}